home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / tools / indent.lha / indent / io.c < prev    next >
C/C++ Source or Header  |  1992-07-06  |  23KB  |  769 lines

  1. /*
  2.  * Copyright 1989 Object Design, Inc.
  3.  * Copyright (c) 1985 Sun Microsystems, Inc.
  4.  * Copyright (c) 1980 The Regents of the University of California.
  5.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by the University of California, Berkeley, the University of Illinois,
  14.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  15.  * or Sun Microsystems may not be used to endorse or promote products
  16.  * derived from this software without specific prior written permission.
  17.  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21.  
  22. #ifndef lint
  23. # ifndef OS2
  24.     static char sccsid[] = "@(#)io.c    6.0 (Berkeley) 92/06/15";
  25. # endif
  26. #endif                          /* not lint */
  27.  
  28. #include "globals.h"
  29. #include <ctype.h>
  30.  
  31. #ifdef OS2                      /* or MSDOS */
  32. #include <string.h>
  33. #include <process.h>
  34. #define bzero(achBuf, cbLength) memset(achBuf, 0, cbLength)
  35. #endif
  36.  
  37. int comment_open;
  38. static paren_target;
  39.  
  40. #ifdef ANSIC
  41. #include <stdarg.h>
  42. static int pad_output(int, int);
  43.  
  44. #endif
  45.  
  46. #ifdef ANSIC
  47. void dump_line(void)
  48. #else
  49. void dump_line()
  50. #endif
  51. {                               /* dump_line is the routine that actually
  52.                                    effects the printing of the new source. It
  53.                                    prints the label section, followed by the
  54.                                    code section with the appropriate nesting
  55.                                    level, followed by any comments */
  56.     register int cur_col, target_col;
  57.     static not_first_line;
  58.  
  59.     if (ps.procname[0])
  60.     {
  61.         if (troff)
  62.         {
  63.             if (comment_open)
  64.             {
  65.                 comment_open = 0;
  66.                 fprintf(output, ".*/\n");
  67.             }
  68.             fprintf(output, ".Pr \"%s\"\n", ps.procname);
  69.         }
  70.         ps.ind_level = 0;
  71.         ps.procname[0] = 0;
  72.     }
  73.     if (s_code == e_code && s_lab == e_lab && s_com == e_com)
  74.     {
  75.         if (suppress_blanklines > 0)
  76.             suppress_blanklines--;
  77.         else
  78.         {
  79.             ps.bl_line = true;
  80.             n_real_blanklines++;
  81.         }
  82.     }
  83.     else if (!inhibit_formatting)
  84.     {
  85.         suppress_blanklines = 0;
  86.         ps.bl_line = false;
  87.         if (prefix_blankline_requested && not_first_line)
  88.             if (swallow_optional_blanklines)
  89.             {
  90.                 if (n_real_blanklines == 1)
  91.                     n_real_blanklines = 0;
  92.             }
  93.             else
  94.             {
  95.                 if (n_real_blanklines == 0)
  96.                     n_real_blanklines = 1;
  97.             }
  98.         while (--n_real_blanklines >= 0)
  99.             putc('\n', output);
  100.         n_real_blanklines = 0;
  101.         if (ps.ind_level == 0)
  102.         {
  103.             if (!btype_3)
  104.                 ps.ind_stmt = 0;/* this is a class A kludge. dont do additional
  105.                                    statement indentation if we are at bracket
  106.                                    level 0 */
  107.             else if (*s_code != '{')
  108.                 ps.ind_stmt = 0;/* this one is a class AA kludge: defeat the
  109.                                    class A kludge if the statement is '{' */
  110.         }
  111.  
  112.         if (e_lab != s_lab || e_code != s_code)
  113.             ++code_lines;       /* keep count of lines with code */
  114.  
  115.  
  116.         if (e_lab != s_lab)
  117.         {                       /* print lab, if any */
  118.             if (comment_open)
  119.             {
  120.                 comment_open = 0;
  121.                 fprintf(output, ".*/\n");
  122.             }
  123.             while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  124.                 e_lab--;
  125.             cur_col = pad_output(1, compute_label_target());
  126.             fprintf(output, "%.*s", e_lab - s_lab, s_lab);
  127.             cur_col = count_spaces(cur_col, s_lab);
  128.         }
  129.         else
  130.             cur_col = 1;        /* there is no label section */
  131.  
  132.         ps.pcase = false;
  133.  
  134.         if (s_code != e_code)
  135.         {                       /* print code section, if any */
  136.             register char *p;
  137.  
  138.             if (comment_open)
  139.             {
  140.                 comment_open = 0;
  141.                 fprintf(output, ".*/\n");
  142.             }
  143.             target_col = compute_code_target();
  144.             {
  145.                 register i;
  146.  
  147.                 for (i = 0; i < ps.p_l_follow; i++)
  148.                     if (ps.paren_indents[i] >= 0)
  149.                         ps.paren_indents[i] = -(short) (ps.paren_indents[i] + target_col);
  150.             }
  151.             cur_col = pad_output(cur_col, target_col);
  152.             for (p = s_code; p < e_code; p++)
  153.                 if (*p == (char) 0200)
  154.                     fprintf(output, "%d", target_col * 7);
  155.                 else
  156.                     putc(*p, output);
  157.             cur_col = count_spaces(cur_col, s_code);
  158.         }
  159.         if (s_com != e_com)
  160.             if (troff)
  161.             {
  162.                 int all_here = 0;
  163.                 register char *p;
  164.  
  165.                 if (ps.cc_comment)
  166.                     all_here++;
  167.                 else if (e_com[-1] == '/' && e_com[-2] == '*')
  168.                     e_com -= 2, all_here++;
  169.                 while (e_com > s_com && e_com[-1] == ' ')
  170.                     e_com--;
  171.                 *e_com = 0;
  172.                 p = s_com;
  173.                 while (*p == ' ')
  174.                     p++;
  175.                 if (p[0] == '/' && (p[1] == '*' || p[1] == '/'))
  176.                     p += 2, all_here++;
  177.                 else if (p[0] == '*')
  178.                     p += p[1] == '/' ? 2 : 1;
  179.                 while (*p == ' ')
  180.                     p++;
  181.                 if (*p == 0)
  182.                     goto inhibit_newline;
  183.                 if (comment_open < 2 && ps.box_com)
  184.                 {
  185.                     comment_open = 0;
  186.                     fprintf(output, ".*/\n");
  187.                 }
  188.                 if (comment_open == 0)
  189.                 {
  190.                     if ('a' <= *p && *p <= 'z')
  191.                         *p += 'A' - 'a';
  192.                     if (e_com - p < 50 && all_here == 2)
  193.                     {
  194.                         register char *follow = p;
  195.  
  196.                         fprintf(output, "\n.nr C! \\w\1");
  197.                         while (follow < e_com)
  198.                         {
  199.                             switch (*follow)
  200.                             {
  201.                             case '\n':
  202.                                 putc(' ', output);
  203.                             case 1:
  204.                                 break;
  205.                             case '\\':
  206.                                 putc('\\', output);
  207.                             default:
  208.                                 putc(*follow, output);
  209.                             }
  210.                             follow++;
  211.                         }
  212.                         putc(1, output);
  213.                     }
  214.                     fprintf(output, "\n./* %dp %d %dp\n",
  215.                             ps.com_col * 7,
  216.                             (s_code != e_code || s_lab != e_lab) - ps.box_com,
  217.                             target_col * 7);
  218.                 }
  219.                 comment_open = 1 + ps.box_com;
  220.                 while (*p)
  221.                 {
  222.                     if (*p == BACKSLASH)
  223.                         putc(BACKSLASH, output);
  224.                     putc(*p++, output);
  225.                 }
  226.             }
  227.             else
  228.             {                   /* print comment, if any */
  229.                 register target = ps.com_col;
  230.                 register char *com_st = s_com;
  231.  
  232.                 target += ps.comment_delta;
  233.                 while (*com_st == '\t')
  234.                     com_st++, target += tabsize;  /* JHT 22oct89 */
  235.                 while (target <= 0)
  236.                     if (*com_st == ' ')
  237.                         target++, com_st++;
  238.                     else if (*com_st == '\t')
  239.                     {
  240.                         target += (tabsize - ((target - 1) % tabsize)); /* JHT 22oct89 */
  241.                         com_st++;
  242.                     }
  243.                     else
  244.                         target = 1;
  245.                 if (cur_col > target)
  246.                 {               /* if comment won't fit on this line, put it on
  247.                                    the next one */
  248.                     putc('\n', output);
  249.                     cur_col = 1;
  250.                     ++ps.out_lines;
  251.                 }
  252.                 while (e_com > com_st && isspace(e_com[-1]))
  253.                     e_com--;
  254.                 cur_col = pad_output(cur_col, target);
  255.                 if (!ps.box_com && !ps.cc_comment)
  256.                 {
  257.                     if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1))
  258.                         if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1)
  259.                             com_st[1] = '*';
  260.                         else
  261.                             fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
  262.                 }
  263.                 fwrite(com_st, e_com - com_st, 1, output);
  264.                 ps.comment_delta = ps.n_comment_delta;
  265.                 cur_col = count_spaces(cur_col, com_st);
  266.                 ++ps.com_lines; /* count lines with comments */
  267.             }
  268.         if (ps.use_ff)
  269.             putc('\014', output);
  270.         else
  271.             putc('\n', output);
  272. inhibit_newline:
  273.         ++ps.out_lines;
  274.         if (ps.just_saw_decl == 1 && blanklines_after_declarations)
  275.         {
  276.             prefix_blankline_requested = 1;
  277.             ps.just_saw_decl = 0;
  278.         }
  279.         else
  280.             prefix_blankline_requested = postfix_blankline_requested;
  281.         postfix_blankline_requested = 0;
  282.     }
  283.     ps.decl_on_line = ps.in_decl; /* if we are in the middle of a declaration,
  284.                                      remember that fact for proper comment
  285.                                      indentation */
  286.     ps.ind_stmt = ps.in_stmt & ~ps.in_decl; /* next line should be indented if
  287.                                                we have not completed this stmt
  288.                                                and if we are not in the middle
  289.                                                of a declaration */
  290.     ps.use_ff = false;
  291.     ps.dumped_decl_indent = 0;
  292.     *(e_lab = s_lab) = '\0';    /* reset buffers */
  293.     *(e_code = s_code) = '\0';
  294.     *(e_com = s_com) = '\0';
  295.     ps.ind_level = ps.i_l_follow;
  296.     ps.paren_level = ps.p_l_follow;
  297.     paren_target = -ps.paren_indents[ps.paren_level - 1];
  298.     not_first_line = 1;
  299.     return;
  300. };
  301.  
  302. #ifdef ANSIC
  303. int compute_code_target(void)
  304. #else
  305. compute_code_target()
  306. #endif
  307. {
  308.     register target_col = ps.ind_size * ps.ind_level + 1;
  309.  
  310.     if (ps.paren_level)
  311.         if (!lineup_to_parens)
  312.             target_col += continuation_indent * ps.paren_level;
  313.         else
  314.         {
  315.             register w;
  316.             register t = paren_target;
  317.  
  318.             if ((w = count_spaces(t, s_code) - max_col) > 0
  319.                 && count_spaces(target_col, s_code) <= max_col)
  320.             {
  321.                 t -= w + 1;
  322.                 if (t > target_col)
  323.                     target_col = t;
  324.             }
  325.             else
  326.                 target_col = t;
  327.         }
  328.     else if (ps.ind_stmt)
  329.         target_col += continuation_indent;
  330.     return target_col;
  331. }
  332.  
  333. #ifdef ANSIC
  334. int compute_label_target(void)
  335. #else
  336. compute_label_target()
  337. #endif
  338. {
  339.     return
  340.         ps.pcase ?
  341.         (cplus && ps.in_decl) ? cplus_ppp_indent
  342.         : (int) (case_ind * ps.ind_size) + 1
  343.         : *s_lab == '#' ? 1
  344.         : ps.ind_size * (ps.ind_level - label_offset) + 1;
  345. }
  346.  
  347.  
  348. /*
  349.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  350.  *
  351.  * All rights reserved
  352.  *
  353.  *
  354.  * NAME: fill_buffer
  355.  *
  356.  * FUNCTION: Reads one block of input into input_buffer
  357.  *
  358.  * HISTORY: initial coding     November 1976    D A Willcox of CAC 1/7/77 A
  359.  * Willcox of CAC    Added check for switch back to partly full input
  360.  * buffer from temporary buffer
  361.  *
  362.  */
  363. #ifdef ANSIC
  364. void fill_buffer(void)
  365. #else
  366. fill_buffer()
  367. #endif
  368. {                               /* this routine reads stuff from the input */
  369.     register char *p;
  370.     register int i;
  371.     register FILE *f = input;
  372.  
  373.     if (bp_save != 0)
  374.     {                           /* there is a partly filled input buffer left */
  375.         buf_ptr = bp_save;      /* dont read anything, just switch buffers */
  376.         buf_end = be_save;
  377.         bp_save = be_save = 0;
  378.         if (buf_ptr < buf_end)
  379.             return;             /* only return if there is really something in
  380.                                    this buffer */
  381.     }
  382.     for (p = buf_ptr = in_buffer; p < &in_buffer[inp_bufs];)
  383.     {
  384.         if ((i = getc(f)) == EOF)
  385.         {
  386.             *p++ = ' ';
  387.             *p++ = '\n';
  388.             if (p >= &in_buffer[inp_bufs])
  389.             {
  390.                 diag(1, "Internal buffer overflow - Line is too long.");
  391.                 fflush(output);
  392.                 exit(1);
  393.             }
  394.             had_eof = true;
  395.             break;
  396.         }
  397.         *p++ = (char) i;
  398.         if (i == '\n')
  399.             break;
  400.     }
  401.     buf_end = p;
  402.     if (p[-2] == '/' && p[-3] == '*')
  403.     {
  404.         if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
  405.             fill_buffer();      /* flush indent error message */
  406.         else
  407.         {
  408.             int com = 0;
  409.  
  410.             p = in_buffer;
  411.             while (*p == ' ' || *p == '\t')
  412.                 p++;
  413.             if (*p == '/' && p[1] == '*')
  414.             {
  415.                 p += 2;
  416.                 while (*p == ' ' || *p == '\t')
  417.                     p++;
  418.                 if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
  419.                     && p[4] == 'N' && p[5] == 'T')
  420.                 {
  421.                     p += 6;
  422.                     if (*p == ':')
  423.                     {
  424. #define MAX_SOURCE_ARG 100
  425.                         char argbuf[MAX_SOURCE_ARG];  /* how big can they get
  426.                                                          ...  */
  427.                         char *a;
  428.  
  429.                         p++;    /* skip the : */
  430.                         /*
  431.                            since set_option changes flags, process pending
  432.                            stuff now
  433.                         */
  434.                         if (s_com != e_com || s_lab != e_lab || s_code != e_code)
  435.                             dump_line();
  436.                         while (1)
  437.                         {
  438.                             a = argbuf; /* accumulate an option */
  439.                             while (*p <= ' ') /* skip whitespace */
  440.                                 p++;
  441.                             if (*p == '*')
  442.                                 break;
  443.                             while (*p > ' ')
  444.                                 *a++ = *p++;
  445.                             *a++ = '\0';
  446.                             set_option(argbuf);
  447.                         }
  448.                         goto End_Magic_Comment;
  449.                     }
  450.                     while (*p == ' ' || *p == '\t')
  451.                         p++;
  452.                     if (*p == '*')
  453.                         com = 1;
  454.                     else if (*p == 'O')
  455.                         if (*++p == 'N')
  456.                             p++, com = 1;
  457.                         else if (*p == 'F' && *++p == 'F')
  458.                             p++, com = 2;
  459.                     while (*p == ' ' || *p == '\t')
  460.                         p++;
  461.                     if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com)
  462.                     {
  463.                         if (s_com != e_com || s_lab != e_lab || s_code != e_code)
  464.                             dump_line();
  465.                         if (!(inhibit_formatting = com - 1))
  466.                         {
  467.                             n_real_blanklines = 0;
  468.                             postfix_blankline_requested = 0;
  469.                             prefix_blankline_requested = 0;
  470.                             suppress_blanklines = 1;
  471.                         }
  472.                     }
  473.                 }
  474.             }
  475.         }
  476.     }
  477. End_Magic_Comment:
  478.     if (inhibit_formatting)
  479.     {
  480.         p = in_buffer;
  481.         do
  482.             putc(*p, output);
  483.         while (*p++ != '\n');
  484.     }
  485.     return;
  486. };
  487.  
  488. /*
  489.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  490.  *
  491.  * All rights reserved
  492.  *
  493.  *
  494.  * NAME: pad_output
  495.  *
  496.  * FUNCTION: Writes tabs and spaces to move the current column up to the desired
  497.  * position.
  498.  *
  499.  * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
  500.  *
  501.  * PARAMETERS: current        integer        The current column target
  502.  * nteger        The desired column
  503.  *
  504.  * RETURNS: Integer value of the new column.  (If current >= target, no action is
  505.  * taken, and current is returned.
  506.  *
  507.  * GLOBALS: None
  508.  *
  509.  * CALLS: write (sys)
  510.  *
  511.  * CALLED BY: dump_line
  512.  *
  513.  * HISTORY: initial coding     November 1976    D A Willcox of CAC
  514.  *
  515.  */
  516.  
  517. #ifdef ANSIC
  518. int pad_output(int current, int target)
  519. #else
  520. pad_output(current, target)
  521.     int current;                /* the current column value */
  522.     int target;                 /* position we want it at */
  523.  
  524. #endif
  525.  /*
  526.     writes tabs and blanks (if necessary) to get the current output position up
  527.     to the target column
  528.  */
  529. {
  530.     register int tstop;         /* Current tab stop being visited */
  531.  
  532.     if (troff)
  533.         fprintf(output, "\\h'|%dp'", (target - 1) * 7);
  534.     else
  535.     {
  536.         if (current >= target)
  537.             return (current);   /* line is already long enough */
  538.  
  539.         if (tabsize > 2)
  540.         {
  541.             /* Compute where next tab stop lies: */
  542.             tstop = current + tabsize - ((current - 1) % tabsize);
  543.  
  544.             for (; tstop <= target; tstop += tabsize)
  545.                 putc('\t', output); /* Tab to each tabstop */
  546.  
  547.             tstop -= tabsize;   /* Account for overshoot */
  548.         }
  549.         else
  550.             tstop = current;
  551.  
  552.         while (tstop++ < target)
  553.             putc(' ', output);  /* Space over to where we want to be */
  554.     }
  555.     return (target);
  556. };
  557.  
  558. /*
  559.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  560.  *
  561.  * All rights reserved
  562.  *
  563.  *
  564.  * NAME: count_spaces
  565.  *
  566.  * FUNCTION: Find out where printing of a given string will leave the current
  567.  * character position on output.
  568.  *
  569.  * ALGORITHM: Run thru input string and add appropriate values to current
  570.  * position.
  571.  *
  572.  * RETURNS: Integer value of position after printing "buffer" starting in column
  573.  * "current".
  574.  *
  575.  * HISTORY: initial coding     November 1976    D A Willcox of CAC
  576.  *
  577.  */
  578.  
  579. #ifdef ANSIC
  580. int count_spaces(int current, char *buffer)
  581. #else
  582. int count_spaces(current, buffer)
  583.     int current;
  584.     char *buffer;
  585.  
  586. #endif
  587. /*
  588.  * this routine figures out where the character position will be after
  589.  * printing the text in buffer starting at column "current"
  590.  */
  591. {
  592.     register char *buf;         /* used to look thru buffer */
  593.     register int cur;           /* current character counter */
  594.  
  595.     cur = current;
  596.  
  597.     for (buf = buffer; *buf != '\0'; ++buf)
  598.     {
  599.         switch (*buf)
  600.         {
  601.  
  602.         case '\n':
  603.         case 014:              /* form feed */
  604.             cur = 1;
  605.             break;
  606.  
  607.         case '\t':
  608.             cur = cur + (tabsize - ((cur - 1) % tabsize));
  609.             break;
  610.  
  611.         case '\b':             /* this is a backspace */
  612.             --cur;
  613.             break;
  614.  
  615.         default:
  616.             ++cur;
  617.             break;
  618.         }                       /* end of switch */
  619.     }                           /* end of for loop */
  620.     return (cur);
  621. };
  622.  
  623. int found_err;
  624.  
  625. #ifdef ANSIC
  626. void diag(int level, char *msg,...)
  627. {
  628.     va_list
  629.         a;
  630.  
  631.     va_start(a, msg);
  632.     if (level)
  633.         found_err = 1;
  634.     if (output == stdout)
  635.     {
  636.         fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
  637.         vfprintf(stdout, msg, a);
  638.         fprintf(stdout, " */\n");
  639.     }
  640.     else
  641.     {
  642.         fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
  643.         vfprintf(stderr, msg, a);
  644.         fprintf(stderr, "\n");
  645.     }
  646. }
  647.  
  648. #else
  649. diag(level, msg, a, b)
  650. {
  651.     if (level)
  652.         found_err = 1;
  653.     if (output == stdout)
  654.     {
  655.         fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
  656.         fprintf(stdout, msg, a, b);
  657.         fprintf(stdout, " */\n");
  658.     }
  659.     else
  660.     {
  661.         fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
  662.         fprintf(stderr, msg, a, b);
  663.         fprintf(stderr, "\n");
  664.     }
  665. }
  666.  
  667. #endif
  668.  
  669. #ifdef ANSIC
  670. void writefdef(struct fstate * f, int nm)
  671. #else
  672. writefdef(f, nm)
  673.     register struct fstate *f;
  674.  
  675. #endif
  676. {
  677.     fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
  678.             nm, f->font, nm, f->size);
  679. }
  680.  
  681. #ifdef ANSIC
  682. char *chfont(struct fstate * of, struct fstate * nf, char *s)
  683. #else
  684. char *
  685.     chfont(of, nf, s)
  686.     register struct fstate *of, *nf;
  687.     char *s;
  688.  
  689. #endif
  690. {
  691.     if (of->font[0] != nf->font[0]
  692.         || of->font[1] != nf->font[1])
  693.     {
  694.         *s++ = '\\';
  695.         *s++ = 'f';
  696.         if (nf->font[1])
  697.         {
  698.             *s++ = '(';
  699.             *s++ = nf->font[0];
  700.             *s++ = nf->font[1];
  701.         }
  702.         else
  703.             *s++ = nf->font[0];
  704.     }
  705.     if (nf->size != of->size)
  706.     {
  707.         *s++ = '\\';
  708.         *s++ = 's';
  709.         if (nf->size < of->size)
  710.         {
  711.             *s++ = '-';
  712.             *s++ = (char) ('0' + of->size - nf->size);
  713.         }
  714.         else
  715.         {
  716.             *s++ = '+';
  717.             *s++ = (char) ('0' + nf->size - of->size);
  718.         }
  719.     }
  720.     return s;
  721. }
  722.  
  723. #ifdef ANSIC
  724. void parsefont(register struct fstate * f, char *s0)
  725. #else
  726. parsefont(f, s0)
  727.     register struct fstate *f;
  728.     char *s0;
  729.  
  730. #endif
  731. {
  732.     register char *s = s0;
  733.     int sizedelta = 0;
  734.  
  735.     bzero(f, sizeof *f);
  736.     while (*s)
  737.     {
  738.         if (isdigit(*s))
  739.             f->size = (char) (f->size * 10 + *s - '0');
  740.         else if (isupper(*s))
  741.             if (f->font[0])
  742.                 f->font[1] = *s;
  743.             else
  744.                 f->font[0] = *s;
  745.         else if (*s == 'c')
  746.             f->allcaps = 1;
  747.         else if (*s == '+')
  748.             sizedelta++;
  749.         else if (*s == '-')
  750.             sizedelta--;
  751.         else
  752.         {
  753.             fprintf(stderr, "indent: bad font specification: %s\n", s0);
  754.             exit(1);
  755.         }
  756.         s++;
  757.     }
  758.     if (f->font[0] == 0)
  759.         f->font[0] = 'R';
  760.     if (bodyf.size == 0)
  761.         bodyf.size = 11;
  762.     if (f->size == 0)
  763.         f->size = (char) (bodyf.size + sizedelta);
  764.     else if (sizedelta > 0)
  765.         f->size += bodyf.size;
  766.     else
  767.         f->size = bodyf.size - f->size;
  768. }
  769.